package org.sosie2.service.test.mule;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URL;
import java.security.cert.Certificate;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Vector;

import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;

import org.apache.axis.Message;
import org.apache.axis.MessageContext;
import org.apache.axis.message.MessageElement;
import org.apache.axis.message.PrefixedQName;
import org.apache.axis.message.SOAPEnvelope;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.xml.security.signature.XMLSignature;
import org.opensaml.SAMLAttribute;
import org.opensaml.SAMLException;
import org.sosie2.service.framework.AbstractService;
import org.sosie2.service.framework.MuleAbstractService;
import org.sosie2.service.framework.SAMLAnnotation;
import org.sosie2.service.framework.SosieException;
import org.sosie2.service.framework.Utils;
import org.w3c.dom.Document;

/**
 * The service adds a new SOAPBodyElement, generates an annotation and appends it to the modified message.
 * 
 * @author gabriela
 * @author oppy
 */
public class MuleSignedAnnotationService extends MuleAbstractService {
	static Logger logger = Logger.getLogger(MuleSignedAnnotationService.class); 
	
	public String KEYSTORE_NAME = "keys/cristian.keystore";
	public static final String KEYSTORE_PASSWORD = "secret";
	public static final String PRINCIPAL_ALIAS = "cristian";
	public static final String PRIVATE_KEY_PASSWORD = "secret";
	
	private String textToAdd = this.getClass().getSimpleName(); 
	
	public void init() {
		Utils instanceUtils = Utils.get();
		URL url = instanceUtils.getFile("configuration//" + Utils.LOGGER_FILE);
		if (url == null)
			logger.info("URL is NULL" );
		else {	
			PropertyConfigurator.configure(url);
		}
	}
	
		
	/**
	 *  A simple constructor
	 */
	public MuleSignedAnnotationService() {
		init();
	}
	
	
	public Message invoke(Message req, Message resp) throws Exception {
		// Retrieve all annotations and verify the digital signatures
		logger.info("Verifying all annotations");
		SAMLAnnotation[] all = this.getAllAnnotations(req.getSOAPEnvelope().getAsDocument());
		if (all != null) // If there are annotations in the message
			for (int i=0; i<all.length; i++)
				all[i].verify();			
		logger.info("All annotations are valid");
				
		// Copy Header
		SOAPHeader header = req.getSOAPHeader();
		copyHeader(header, resp.getSOAPHeader());
		
		// Copy Body
//		resp = messageContext.getResponseMessage().getSOAPEnvelope();
		copyBody(req.getSOAPBody(), resp.getSOAPBody());
		
		// Add a tag to the body				
		SOAPBody respBody = resp.getSOAPBody();
		SOAPBodyElement e = respBody.addBodyElement(new PrefixedQName("http://unibw.de/sosie", textToAdd, "sosie"));				
		e.addTextNode("Timestamp: " + (new Date()));
    		
		// Create dummy attributeNames - attributeValues hashMap		
		String[][] att = new String[1][2];
		att[0][0] = "DummyAttribute";
		att[0][1] = "DummyValue";
		
		// Create the annotation
		SAMLAnnotation sa = new SAMLAnnotation(att, "http://unibw.de/sosie/test/AnnotationServiceTest", "http://unibw.de/sosie/next");
		
		// Retrieve private key + certificates in for signature
		KeyStore ks = KeyStore.getInstance("JKS");	   
	    java.io.InputStream is = getClass().getClassLoader().getResourceAsStream(KEYSTORE_NAME);
	    ks.load(is, KEYSTORE_PASSWORD.toCharArray());
	    is.close();
		
	    // retrive the license manager key
	    KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry) ks.getEntry(PRINCIPAL_ALIAS, 
	    		new KeyStore.PasswordProtection(PRIVATE_KEY_PASSWORD.toCharArray()));
	    PrivateKey lmPrivateKey = pkEntry.getPrivateKey();
	    
	    // retrive the certificate of the license manager
	    Vector<Certificate> certs = new Vector<Certificate>();	    
	    Certificate[] certsArray = ks.getCertificateChain(PRINCIPAL_ALIAS);
	    for (int i = 0; i < certsArray.length; i++)
	    	certs.add(certsArray[i]);

		sa.sign(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1, lmPrivateKey, certs);
		// ---------- finish digital signature -------------
		
		
		Document doc = resp.getSOAPEnvelope().getAsDocument();
		doc = addAnnotation(doc, sa, "http://unibw.de/sosie/dummyAnnotationService");
		SOAPMessage soapMsg = Utils.toMessage(doc);
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		soapMsg.writeTo(out);
				
		//set the response message 
		Message msg = new Message(new ByteArrayInputStream(out.toByteArray()), false);	    		
	    
	    logger.info("finished");
	    
		return msg;
    }
	
}
